package com.byron.media.server.sessions;

import com.byron.media.server.handlers.UdpMediaDataSender;
import com.byron.media.server.model.MediaData;
import com.byron.media.server.model.MediaHeaderObj;
import com.byron.media.server.model.SeqFactory;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

@Slf4j
public class SessionContainer {

    private Map<String, Group> groupMap = new ConcurrentHashMap<>();

    private Map<Long, ISession> sessionMap = new ConcurrentHashMap<>();

    private Set<IProxyServer> proxyServers = new HashSet<>();       // 代理服务器

    private Set<IProxyServer> readyProxyServers = new HashSet<>();

    private Set<IProxyServer> leavingProxyServers = new HashSet<>();



    private Set<IProxyClient> proxyClients = new HashSet<>();       // 代理客户端

    private Set<IProxyClient> readyProxyClients = new HashSet<>();

    private Set<IProxyClient> leavingProxyClients = new HashSet<>();

    /**
     * 添加到列表中
     * @param proxyServer
     */
    public void addToProxy(IProxyServer proxyServer){
        synchronized (SessionContainer.this){
            readyProxyServers.add(proxyServer);
        }
    }


    /**
     * 根据组的名字获取组
     */
    public Group getGroup(String groupName) {
        return groupMap.get(groupName);
    }

    /**
     * 添加到列表中
     * @param proxyServer
     */
    public void removeFromPoxy(IProxyServer proxyServer){
        synchronized (SessionContainer.this){
            leavingProxyServers.add(proxyServer);
        }
    }


    /**
     * 添加到组
     */
    public Group addToGroup(long sessionName, String group, ISession session){
        Group g = groupMap.computeIfAbsent(group, (k) -> new Group(group));
        g.addToGroup(sessionName, session);
        sessionMap.put(sessionName, session);
        return g;
    }


    /**
     * 从组移除
     */
    public void removeFromGroup(long sessionName, String group, ISession session){
        Group g = groupMap.computeIfAbsent(group, (k) -> new Group(group));
        g.removeFromGroup(sessionName, session);
        sessionMap.remove(sessionName);
    }


//    /**
//     * 发送给其他终端
//     */
//    public void sendToOther(ISession me, String group, MediaData data) {
//        Group g = groupMap.computeIfAbsent(group, (k) -> new Group(group));
//        g.sendToOthers(me, data);
//
//        // 发送到组播
////        UdpMediaDataSender sender = senderMap.get(group);
////        if(sender != null){
////            if(MediaType.isPCM(data.getType())){
////                return;
////            }
////            if(MediaType.isAAC(data.getType())){
////                return;
////            }
////            sender.pushFrameInfo(data);
////        }
//    }

    /**
     * 发送最上一次I帧，让客户端恢复界面
     * @param session
     */
    public void sendLastIframe(String group, ISession session) {
        Group g = groupMap.computeIfAbsent(group, (k) -> new Group(group));
        g.sendLastIframe(session);
    }



    /**
     * 初始化udpsender
     * @param groupName
     */
    public synchronized void initUdpSender(String groupName) {
//        UdpMediaDataSender udpSender = senderMap.get(groupName);
//        if(udpSender != null){
//            return;
//        }
//
//        String[] temp = groupName.split(":");
//        String groupAddress = temp[0];
//        int port = Integer.parseInt(temp[1]);
//        udpSender = new UdpMediaDataSender(groupAddress, port);
//        udpSender.start();
//        senderMap.put(groupName, udpSender);
    }

    /**
     * 根据sessionName获取session
     */
    public ISession getSessionByName(long sessionName) {
        return sessionMap.get(sessionName);
    }

    /**
     * 组调用，释放该组的数据
     * @param group
     */
    void removeGroup(Group group) {
        groupMap.remove(group.getGroupName());
    }


    private static SessionContainer instance;

    public static SessionContainer getInstance() {
        if (instance == null) {
            synchronized (SessionContainer.class) {
                if (instance == null) {
                    instance = new SessionContainer();
                }
            }
        }
        return instance;
    }

    /**
     * 将注册消息发送给其他代理服务器
     * @param header
     */
    public void sendToProxyClient(MediaHeaderObj header) {
        if(!readyProxyServers.isEmpty()){
            synchronized (SessionContainer.this){
                for(IProxyServer p : readyProxyServers){
                    proxyServers.add(p);
                }
                readyProxyServers.clear();
            }
        }
        if(!leavingProxyServers.isEmpty()){
            synchronized (SessionContainer.this){
                for(IProxyServer p : leavingProxyServers){
                    proxyServers.remove(p);
                }
                leavingProxyServers.clear();
            }
        }

        byte seq = SeqFactory.getInstance().generalSeq();
        proxyServers.forEach(p -> {
            p.write(seq, header);
        });
    }

    /**
     * 添加代理客户端
     */
    public void addToProxyClient(IProxyClient proxyClient) {
        synchronized (SessionContainer.this){
            readyProxyClients.add(proxyClient);
        }
    }

    /**
     * 移除代理客户端
     */
    public void removeFromProxyClient(IProxyClient proxyClient) {
        synchronized (SessionContainer.this){
            leavingProxyClients.add(proxyClient);
        }
    }

    /**
     * 将注册消息发送给其他代理服务器
     * @param header
     */
    public void sendToProxyServer(MediaHeaderObj header) {
        if(!readyProxyClients.isEmpty()){
            synchronized (SessionContainer.this){
                for(IProxyClient p : readyProxyClients){
                    proxyClients.add(p);
                }
                readyProxyClients.clear();
            }
        }
        if(!leavingProxyClients.isEmpty()){
            synchronized (SessionContainer.this){
                for(IProxyClient p : leavingProxyClients){
                    proxyClients.remove(p);
                }
                leavingProxyClients.clear();
            }
        }

        byte seq = SeqFactory.getInstance().generalSeq();
        proxyClients.forEach(p -> {
            p.write(seq, header);
        });
    }

}
